package carcassonne.server.ioc;

import carcassonne.server.http.HttpContext;
import carcassonne.server.http.HttpParams;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

public class HttpMessageDispatcher extends AbsMessageDispatcher {

    public HttpMessageDispatcher(List<Object> controllers) {
        super(controllers);
    }

    @Override
    protected void MappingMVC() {

        for (Object controller : Controllers) {
            Class<?> clazz = controller.getClass();

            RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
            String controllerPath = requestMapping.value();

            Method[] methods = clazz.getMethods();

            for (Method method : methods) {
                if (!method.isAnnotationPresent(HttpMessageHandler.class)) continue;

                HttpMessageHandler handler = method.getAnnotation(HttpMessageHandler.class);
                String methodPath = handler.path();
                String requestPath = controllerPath + methodPath;
                controllerMapping.put(requestPath, controller);
                switch (handler.method()) {
                    case Get -> GetFunctions.put(requestPath, new MethodInfo(method, handler.params()));
                    case Post -> PostFunctions.put(requestPath, new MethodInfo(method, handler.params()));
                    case Put -> PutFunctions.put(requestPath, new MethodInfo(method, handler.params()));
                    case Delete -> DeleteFunctions.put(requestPath, new MethodInfo(method, handler.params()));
                }
            }
        }
    }

    public boolean Has(String path) {
        return controllerMapping.containsKey(path);
    }

    public static final int Get = 1;
    public static final int Post = 2;
    public static final int Put = 3;
    public static final int Delete = 4;

    public void HandleGet(String path, HttpContext context, HttpParams params) {
        HandleHttpRequest(path, context, params, GetFunctions);
    }

    public void HandlePost(String path, HttpContext context, HttpParams params) {
        HandleHttpRequest(path, context, params, PostFunctions);
    }

    public void HandlePut(String path, HttpContext context, HttpParams params) {
        HandleHttpRequest(path, context, params, PutFunctions);
    }

    public void HandleDelete(String path, HttpContext context, HttpParams params) {
        HandleHttpRequest(path, context, params, DeleteFunctions);
    }

    protected void HandleHttpRequest(String path, HttpContext context, HttpParams params, Map<String, MethodInfo> methodMap) {
        Object controller = controllerMapping.get(path);
        if (!methodMap.containsKey(path)) {
            context.ResponseForbidden("method with path <" + path + "> not found!");
            return;
        }
        methodMap.get(path).Invoke(controller, context, params);
    }
}
